/*
* @(#)FileSystemContentStoreHandler.java
*
* Copyright (c) 2003 DCIVision Ltd
* All rights reserved.
*
* This software is the confidential and proprietary information of DCIVision
* Ltd ("Confidential Information").  You shall not disclose such Confidential
* Information and shall use it only in accordance with the terms of the license
* agreement you entered into with DCIVision Ltd.
*/
package com.dcivision.dms.core;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLConnection;
import java.sql.Connection;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.impl.LogFactoryImpl;

import com.dcivision.dms.DmsErrorConstant;
import com.dcivision.dms.DmsOperationConstant;
import com.dcivision.framework.SessionContainer;
import com.dcivision.framework.SystemParameterConstant;
import com.dcivision.framework.SystemParameterFactory;



/**
 * <p>Class Name:       FileSystemContentStoreHandler.java    </p>
 * <p>Description:      The class mainly handle the file type storage for DMS dmsDocument content.</p>
 * @author              Zoe Shum
 * @company             DCIVision Limited
 * @creation date       01/08/2003
 * @version             $Revision: 1.19 $
 */

public class FileSystemContentStoreHandler implements DmsContentStoreHandler {

  public static final String REVISION = "$Revision: 1.19 $";
  

  protected Log log = new LogFactoryImpl().getInstance(this.getClass());
  private DocumentProperties properties;
  private InputStream inputStream;
  private Object[] objs;
  private String documentPath = DmsOperationConstant.documentPath;
  private String segmentFolderName = DmsOperationConstant.segment;
   
  private Connection conn;
  private SessionContainer sessionContainer;
  
  

  /**
   *  Constructor - Creates a new instance of FileSystemContentStoreHandler
   */
  public FileSystemContentStoreHandler() {
    this.properties = new DocumentProperties();
  }
  

  /**
   *  Constructor - Creates a new instance of FileSystemContentStoreHandler
   *                specifying the objects
   */          
  public FileSystemContentStoreHandler(Object[] objs) {
    this();
    this.objs = objs;
  }

  /**
   *  Constructor - Creates a new instance of FileSystemContentStoreHandler 
   *                specifying the properties
   */
  public FileSystemContentStoreHandler(DocumentProperties properties) {
    this.properties = properties;
  }

  public void setProperties(DocumentProperties properties) {
    this.properties = properties;
  }

  public void setProperty(String property, Object propertyValue) {
    properties.setProperty(property, propertyValue);
  }

  public Object getProperty(String propertyName) {
    return properties.getProperty(propertyName);
  }

  public DocumentProperties getProperties() {
    return properties;
  }

  
  /**
   * Gets the content type of the file which the file name specified in the
   * DocumentProperties (DmsContentStoreHandler.FILE_NAME_PROPERTY)
   * 
   * 
   * @return the content type of the file
   * @see com.dcivision.dms.core.DmsContentStoreHandler
   * @see com.dcivision.dms.DocumentProperties
   */
  public String getContentType() {
    String fileName = (String) properties.getProperty(DmsContentStoreHandler.FILE_NAME_PROPERTY);
    return URLConnection.guessContentTypeFromName(fileName);
  }


   /**
   * Gets the file Extension of the file which the file name specified in the
   * DocumentProperties (DmsContentStoreHandler.FILE_NAME_PROPERTY)
   * 
   * 
   * @return the content type of the file
   * @see com.dcivision.dms.core.DmsContentStoreHandler
   * @see com.dcivision.dms.DocumentProperties
   */
  public String getExtension() {
    String fileName = (String) properties.getProperty(DmsContentStoreHandler.FILE_NAME_PROPERTY);
    String extension = null;
    int position = 0;
    if ((position = fileName.lastIndexOf(".")) != -1) {
      extension = fileName.substring(position, fileName.length());
    }
    return extension;
  }

  
  /**
   * Reads the file content into an inputStream which the file path and name 
   * are specified in the properties DocumentProperties (DmsContentStoreHandler.FILE_NAME_PROPERTY)
   * 
   * @return java.io.InputStream of the file content
   * @throws ContentStoreException 
   * @see com.dcivision.dms.core.DmsContentStoreHandler
   * @see com.dcivision.dms.DocumentProperties
   * @see com.dcivision.dms.core.ContentStoreException
   */
  public InputStream readStream() throws ContentStoreException {
    String directory = (String) properties.getProperty(DmsContentStoreHandler.FILE_PHYSICAL_PATH);
    String fileName = (String) properties.getProperty(DmsContentStoreHandler.FILE_NAME_PROPERTY);

    if (directory == null || fileName == null) {
      throw new ContentStoreException(DmsErrorConstant.CONTENT_STORE_HANDLER_ERROR_MISSING_PARAMETER);
    }
    
    Integer segmentNo = (Integer) properties.getProperty(DmsContentStoreHandler.SEGMENTNUM_PROPERTY);
    if (segmentNo != null){
    	String segmentPath = this.documentPath +"/" + this.segmentFolderName +  segmentNo + "/";
    	directory += segmentPath;
    }
    
    if (directory.charAt(directory.length() - 1) != File.separatorChar && directory.charAt(directory.length() - 1) != '/') {
      directory = directory + System.getProperty("file.separator");
    }
    File file = new File(directory + fileName);
    if (!file.exists()) {
      log.debug(file.getAbsolutePath());
      throw new ContentStoreException(DmsErrorConstant.CONTENT_STORE_HANDLER_ERROR_FILE_NOT_FIND);
    }
    InputStream inputStream = null;
    try {
      inputStream = new FileInputStream(file);
    } catch (FileNotFoundException fnfe) {
      throw new ContentStoreException(DmsErrorConstant.CONTENT_STORE_HANDLER_ERROR_FILE_NOT_FIND);
    } catch (IOException ioe) {
      log.error(ioe, ioe);
      throw new ContentStoreException(DmsErrorConstant.CONTENT_STORE_HANDLER_ERROR_READ_FAILED);
    }
    return inputStream;
  }

  
  /**
   * Reads the file content into an byte array which the file path and name 
   * are specified in the properties DocumentProperties 
   * (DmsContentStoreHandler.FILE_PHYSICAL_PATH,DmsContentStoreHandler.FILE_NAME_PROPERTY)
   * 
   * @return byte array of the file content
   * @throws ContentStoreException 
   * @see com.dcivision.dms.core.DmsContentStoreHandler
   * @see com.dcivision.dms.DocumentProperties
   * @see com.dcivision.dms.core.ContentStoreException
   */
  public byte[] read() throws ContentStoreException {
    String directory = (String) properties.getProperty(DmsContentStoreHandler.FILE_PHYSICAL_PATH);
    String fileName = (String) properties.getProperty(DmsContentStoreHandler.FILE_NAME_PROPERTY);

    if (directory == null || fileName == null) {
      throw new ContentStoreException(DmsErrorConstant.CONTENT_STORE_HANDLER_ERROR_MISSING_PARAMETER);
    }
    
    Integer segmentNo = (Integer) properties.getProperty(DmsContentStoreHandler.SEGMENTNUM_PROPERTY);
    if (segmentNo != null){
    	String segmentPath = this.documentPath +"/" + this.segmentFolderName +  segmentNo + "/";
    	directory += segmentPath;
    }

    if (directory.charAt(directory.length() - 1) != File.separatorChar && directory.charAt(directory.length() - 1) != '/') {
      directory = directory + System.getProperty("file.separator");
    }

    File file = new File(directory + fileName);
    if (!file.exists()) {
      throw new ContentStoreException(DmsErrorConstant.CONTENT_STORE_HANDLER_ERROR_FILE_NOT_FIND);
    }
    FileInputStream fis = null;
    ByteArrayOutputStream baos = null;
    byte[] data = null;
    try {
      fis = new FileInputStream(file);
      baos = new ByteArrayOutputStream();

      int bufferSize = fis.available();
      byte[] buffer = new byte[bufferSize];
      int length = -1;

      while ((length = fis.read(buffer, 0, bufferSize)) != -1) {
        baos.write(buffer, 0, length);
      }

      data = baos.toByteArray();
      return data;
    } catch (FileNotFoundException fnfe) {
      throw new ContentStoreException(DmsErrorConstant.CONTENT_STORE_HANDLER_ERROR_FILE_NOT_FIND);
    } catch (IOException ioe) {
      log.error(ioe, ioe);
      throw new ContentStoreException(DmsErrorConstant.CONTENT_STORE_HANDLER_ERROR_READ_FAILED);
    } finally {
      try { baos.close(); } catch (IOException ioe) {} finally { baos = null; }
      try { fis.close(); } catch (IOException ioe) {} finally { fis = null; }
    }
  }

  /**
   * 
   * Writes the inputStream specified in properties (DmsContentStoreHandler.FILE_CONTENT_PROPERTY) 
   * into the file with path and name specified in properties 
   * (DmsContentStoreHandler.FILE_PHYSICAL_PATH, DmsContentStoreHandler.FILE_NAME_PROPERTY) respectively.
   * 
   * 
   * @throws ContentStoreException 
   * @see com.dcivision.dms.core.DmsContentStoreHandler
   * @see com.dcivision.dms.DocumentProperties
   * @see com.dcivision.dms.core.ContentStoreException
   */
  public void write() throws ContentStoreException {
	  String directory = (String) properties.getProperty(DmsContentStoreHandler.FILE_PHYSICAL_PATH);
	  String fileName = (String) properties.getProperty(DmsContentStoreHandler.FILE_NAME_PROPERTY);
    Integer segmentNO = (Integer) properties.getProperty(DmsContentStoreHandler.SEGMENTNUM_PROPERTY);
    
	  if (directory == null || fileName == null) {
		  throw new ContentStoreException(DmsErrorConstant.CONTENT_STORE_HANDLER_ERROR_MISSING_PARAMETER);
	  }
	  
	  File dirFile = new File(directory);
	  if (!dirFile.exists()){
		  dirFile.mkdirs();
	  }

    int segmentNumInt = segmentNO != null?segmentNO.intValue():0;
	  Integer rolloverLimit = SystemParameterFactory.getSystemParameterInteger(SystemParameterConstant.DMS_FILE_ROLLOVER_LIMIT);
	  if (rolloverLimit.intValue() > 0){
		  String docPath = directory + this.documentPath + "/" + this.segmentFolderName + segmentNumInt + "/";
		  File docFile = new File(docPath);
		  if (!docFile.exists()){
			  docFile.mkdirs();
		  }
		  File[] docFileList = docFile.listFiles();
		  
		  if (docFileList.length >= rolloverLimit.intValue()){
        segmentNumInt++;
			  docPath = directory + this.documentPath + "/" + this.segmentFolderName + segmentNumInt + "/";
			  File sudDocFile = new File(docPath);
			  sudDocFile.mkdirs();
		  }
		  directory = docPath;
		  properties.setProperty(DmsContentStoreHandler.SEGMENTNUM_PROPERTY,new Integer(segmentNumInt));      
	  }   
	  
	  FileOutputStream fos = null;
	  InputStream inputStream = null;
	  try {
		  if (directory.charAt(directory.length() - 1) != File.separatorChar && directory.charAt(directory.length() - 1) != '/') {
			  directory = directory + System.getProperty("file.separator");
		  }
		  inputStream = (InputStream) properties.getProperty(DmsContentStoreHandler.FILE_CONTENT_PROPERTY);
		  fos = new FileOutputStream(directory + fileName);
		  
		  int bufferSize = 8192;
		  byte[] buffer = new byte[bufferSize];
		  int length = -1;
		  
		  while ((length = inputStream.read(buffer, 0, bufferSize)) != -1) {
			  fos.write(buffer, 0, length);
			  fos.flush();
		  }
    } catch (IOException ioe) {
      log.error(ioe, ioe);
      throw new ContentStoreException(DmsErrorConstant.CONTENT_STORE_HANDLER_ERROR_WRITE_FAILED);
	  } finally {
		  try { inputStream.close(); } catch (IOException ioe) {} finally { inputStream = null; }
		  try { fos.close(); } catch (IOException ioe) {} finally { fos = null; }
	  }
  }
  
  /**
   * Delete the physical file that the file name and path specified in properties 
   * (DmsContentStoreHandler.FILE_PHYSICAL_PATH, DmsContentStoreHandler.FILE_NAME_PROPERTY) respectively.
   * 
   * @throws ContentStoreException 
   * @see com.dcivision.dms.core.DmsContentStoreHandler
   * @see com.dcivision.dms.DocumentProperties
   * @see com.dcivision.dms.core.ContentStoreException
   */

  public void delete() throws ContentStoreException {
    String directory = (String) properties.getProperty(DmsContentStoreHandler.FILE_PHYSICAL_PATH);
    String fileName = (String) properties.getProperty(DmsContentStoreHandler.FILE_NAME_PROPERTY);
    Integer segmentNumber = (Integer) properties.getProperty(DmsContentStoreHandler.SEGMENTNUM_PROPERTY);

    if (directory == null || fileName == null) {
      throw new ContentStoreException(DmsErrorConstant.CONTENT_STORE_HANDLER_ERROR_MISSING_PARAMETER);
    }

    File f = null;
    if (directory.charAt(directory.length() - 1) != File.separatorChar
        && directory.charAt(directory.length() - 1) != '/') {
      directory = directory + System.getProperty("file.separator");
    }

   
    if (segmentNumber != null){
      String segmentPath = this.documentPath +"/" + this.segmentFolderName +  segmentNumber + "/";
      directory += segmentPath;
    }       
    
    String docPath = directory + fileName;
    f = new File(docPath);

    if (!f.exists()) {
      throw new ContentStoreException(DmsErrorConstant.CONTENT_STORE_HANDLER_ERROR_FILE_NOT_FIND);
    }
    if (!f.delete()) {
      // queue to schedule deleteion again, reason : FIS reading lock
      throw new ContentStoreException(DmsErrorConstant.CONTENT_STORE_HANDLER_ERROR_DELETED_FAILED);
    }
  }

  public void rename() throws ContentStoreException {
    
    String directory = (String) properties.getProperty(DmsContentStoreHandler.FILE_PHYSICAL_PATH);
    Integer segmentNumber = (Integer) properties.getProperty(DmsContentStoreHandler.SEGMENTNUM_PROPERTY);
    String oldFileName = (String) properties.getProperty(DmsContentStoreHandler.FILE_NAME_PROPERTY);
    String newFileName = (String) properties.getProperty(DmsContentStoreHandler.NEW_FILE_NAME);    

    if (directory == null || oldFileName == null) {
      throw new ContentStoreException(DmsErrorConstant.CONTENT_STORE_HANDLER_ERROR_MISSING_PARAMETER);
    }

    File oldDocumentFile = null;
    File newDocumentFile = null;    
    if (directory.charAt(directory.length() - 1) != File.separatorChar
        && directory.charAt(directory.length() - 1) != '/') {
      directory = directory + System.getProperty("file.separator");
    }


    if (segmentNumber != null){
      String segmentPath = this.documentPath +"/" + this.segmentFolderName +  segmentNumber + "/";
      directory += segmentPath;
    }    
    
    
    String oldFilePath = directory + oldFileName;
    String newFilePath = directory + newFileName;
    oldDocumentFile = new File(oldFilePath);
    newDocumentFile = new File(newFilePath);

    if (!oldDocumentFile.exists()){
      throw new ContentStoreException(DmsErrorConstant.CONTENT_STORE_HANDLER_ERROR_DELETED_FAILED);      
    }
    if(newDocumentFile.exists() ) {
      throw new ContentStoreException(DmsErrorConstant.CONTENT_STORE_HANDLER_ERROR_FILE_EXIST);
    }
    if (!oldDocumentFile.renameTo(newDocumentFile)) {
      // queue to schedule deleteion again, reason : FIS reading lock
      throw new ContentStoreException(DmsErrorConstant.CONTENT_STORE_HANDLER_ERROR_RENAME_FAILED);
    }
  }  
  
  public void close() throws ContentStoreException {    
  }
}
